﻿using System.Collections.Concurrent;

namespace BPM.Web.Monitor;

/// <summary>
/// A ConcurrentQueue based simple circular buffer implementation.
/// </summary>
internal class CircularBuffer<T> : ICircularBuffer<T>
{
    private readonly ConcurrentQueue<T> _queue = new();
    private readonly Func<T, bool> _shouldBeExcluded;
    private readonly int _size;

    /// <summary>
    /// Initializes a <see cref="CircularBuffer{T}"/>.
    /// </summary>
    /// <param name="size">The size of the circular buffer.</param>
    /// <param name="shouldBeExcluded">Whether or not, an item should not be saved in circular buffer.</param>
    public CircularBuffer(int size = 100, Func<T, bool>? shouldBeExcluded = null)
    {
        _size = size;
        _shouldBeExcluded = shouldBeExcluded ?? (_ => true);
    }

    /// <summary>
    /// Adds an item to buffer.
    /// </summary>
    /// <param name="item"></param>
    public void Add(T item)
    {
        if (_size <= 0)
            return;

        if (_shouldBeExcluded(item))
        {
            _queue.Enqueue(item);
            if (_queue.Count > _size)
            {
                _ = _queue.TryDequeue(out _);
            }
        }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => _queue.GetEnumerator();

    IEnumerator<T> IEnumerable<T>.GetEnumerator() => _queue.GetEnumerator();
}
